=================================
  TILE CUTTER for Spectrum Next
(...or CSpect, at the very least)
 J. Waterman  11-14 January 2023
=================================

This program has been written as part of my learning process of Next BASIC and
its various additions over regular Spectrum BASIC, not least the new graphics
modes. Completely colour-clash-free LAYER 2 looks to be particularly useful,
but one of its potentially best features is not explained very well in the
Issue 1 manual (albeit that I'm still grateful to Phoebus Dokos for writing it
and Henrique Olifiers for handing out free copies to Issue 2 backers at Crash
Live).

IN SUMMARY:
Draw your tiles in the graphics package of your choosing, convert it to a
Next-compatible SL2 file, and this program will cut the TOP THIRD of the screen
(BANK 9) into tiles for use in Next programs. See immediately below for more
detailed instructions.

Inluded are the following files:
- TILECUT.BAS is the Next BASIC program, the only file that actually has to be
  installed on the Next.
- TILECUT.TXT is the program listing converted to PC-readable text with
  NextZXOS' .bas2txt command.
- RGBTEST.SL2 is a screen of red, blue and green colour gradients designed to
  show the slight issue with Remy Sharp's SL2 conversion tools when certain RGB
  values are encountered, as mentioned in the "Custom GIMP palette" section.
- TILETEST.SL2 is a set of example tiles, taken from TimeTrax (BRIGHT 0 magenta
  & yellow, colour level B6h), Dark Empire (BRIGHT 1 white, blue & red, colour
  level FFh) and Super Mario Bros. 3 (with the un-Spectrum-like palette used on
  the NES converted satisfactorily into Next format, and with some sprites
  included featuring transparency).

================================================================================


Instructions for the program, and how it works
----------------------------------------------

1.  Copy the folder "TILECUT" to the root directory on the SD card.
2.  Draw your tiles in the graphics package of your choosing. Anything that can
    save as a .BMP file will do - GIMP, Photoshop, Inkscape, MS Paint - even the
    version packaged with Windows 3.1 should do the job.
    NOTE that the Tile Cutter operates on the TOP THIRD of the screen, i.e.
    256×64 pixels, but the Next file format requires that the input file is
    256×192 pixels - so make sure the bitmap is that size and leave the bottom
    two thirds blank.
3.  Make sure the drawing is 256 pixels wide and 192 pixels high. Save this in
    .BMP format. Do not worry about the colour palette at this stage - a 24-bit
    bitmap will still work (which will be 147,578 bytes).
    BUT - note there is a warning about "midpoint" colours below. To see this
    warning and to ensure the colours are correct from the start, see the
    section marked "Custom GIMP palette".
4.  Convert the bitmap to SL2 format with Remy Sharp's Next Tools:
    https://zx.remysharp.com/tools/ (these are allegedly usable offline...)
    Under "ZX Next image conversion", select "Modify to use default L2 colours",
    then "Choose File" and select the bitmap you've just drawn. Select "SL2",
    and keep the filename limited to eight characters.
5.  Retrieve the insta-downloaded .SL2 file from your Downloads folder and copy
    it to the TILECUT folder on the CSpect SD card image. (See the HDFmonkey
    section below, again, if you need a reminder). Make sure both "TILECUT.BAS"
    and the .SL2 file are in the "TILECUT" folder.
6.  Select Next BASIC. CD "TILECUT" then LOAD "TILECUT.BAS".
7.  Choose from the menu: load an external .SL2 file (i.e. the one you've just
    made and uploaded to the SD card image), view the list of .SL2 files in the
    "TILECUT" folder, or draw the test tiles that are provided to demonstrate
    how the program works.
8.  If you've selected "load" (as you most likely will), input the name of the
    .SL2 file, without its extension (which will automatically be added). Any
    input longer than 8 characters will be shortened, and if the file is not
    found, you can try again or restart the program to view the list of
    available files.
9.  Select the tile size, 8×8 or 16×16 - any bitmap can be cut to either tile
    size - though if you've selected to draw the test tiles, an appropriate
    set of 64 16×16 tiles or 256 8×8 tiles will be drawn.

    Now watch the tiles being cut in the centre of the screen...

10. When the tiles have been cut and tested, input a filename - 8 characters at
    most - to save the tiles to a .BIN file. Any name longer than 8 characters
    will be automatically shortened.
11. Input the number of tiles to save, up to the default maximum (64 16×16
    tiles or 256 8×8 tiles); any number larger than this will be set to the
    default. The .BIN file saved will be smaller, the fewer tiles are saved,
    allowing for unused space in the tile bank to be used for other purposes.
    NOTE that the tile map is not saved - draw one yourself when you need it,
    and see the "More technically..." section for a description of what to do.


Memory banks
------------

To keep this program compatible with an unexpanded Next, I have used the highest
two BANKs that are available to every machine - these are BANKs 47 (used as the
tile bank) and 46 (for the tile map). Owners of expanded Nexts can change the
variables %b and %m in line 30 to higher values - or use the program as-is and
reload saved tiles to a different BANK.


Important note on transparency
------------------------------

This program has been tested with Spectrum graphics as tiles, hence the default
setting of "bright magenta" (#FF00FF) as the transparency colour has been
changed. #B66D6D (palette entry 173/ADh, a filthy salmon pink) has been chosen
as the transparency colour; it is unlikely to be used by anyone with good taste.
To revert to the default transparency, change variable %t in line 60 to 227/E3h.

In the sets of test tiles, the INK of tile 18 and the PAPER of tile 45 in the
large set, and the INK of tile 52h and the PAPER of tile ADh in the small set,
appear transparent.


Custom GIMP palette
-------------------

Remy Sharp's .SL2 conversion tool is excellent - but convert RGBTEST.BMP that
is included with this package, and load it into the Next to see a problem:
LAYER 2,1: LOAD "RGBTEST.SL2" LAYER
The four levels of blue and the eight levels of green and red are visible and
clearly separated, but there are raggedy edges between the levels of each
colour. I can only assume that the conversion algorithm has found values that
are the exact mean of the allowable values (00, 24, 49, 6D, 92, B6, DB, FF for
red and green; 00, 6D, B6 and FF for blue) and has arbitrarily chosen to step up
or down one level each time it encounters one of these mean values, rather than
consistently falling on one specific side of the divide. Seeing as we are
dealing with rigidly-defined tile graphics here rather than attempting to put
photographs on the Next screen, ideally there needs to be a way to sort out the
colours before sending the image for .SL2 conversion.

Hence, for those who want to make sure that only Next layer 2 colours are used
right from the start, I have provided a custom palette for use in GIMP, with the
correct levels of red, green and blue predefined, taken from screenshots of
CSpect. This is the file "SpecNext.gpl" and should be copied to the Palette
folder. On my installation it can be found here:
C:\Program Files\GIMP 2\share\gimp\2.0\palettes
If this doesn't exist, search for GIMP's existing custom palettes ("Ega.gpl",
"Pastels.gpl", "Greens.gpl") and that'll turn up the palette folder.


================================================================================


Installation instructions for CSpect
------------------------------------

I do not own a real Next yet. Apparently, the delivery date is still on for late
summer, or early autumn 2023. CSpect is the most capable Next emulator but can
be a bit finnicky to set up, and requires the use of a virtual SD card image.

If you don't have that SD card image already (how did you expect to get Next
emulation working without it?), download a pre-made image with all the files
needed to make a Next work properly, from https://zxspectrumnext.online - use
the "CSPECT Next distribution 2Gb SD Card Image", which will unzip to a file
cspect-next-2gb.img. Rename it if you want (I renamed mine SD1.IMG - make sure
to change the filename every time it's required in the guide below.)

Also, Mac and Linux users, you're on your own for the installation and use of
anything mentioned below - I know a bit about the use of ./ and CHMOD to execute
files and they'll be .SH instead of .BAT, but when it comes to compiling from
source, that's several orders of magnitude above my pay grade. Deal with it.

1.  First, in NextBASIC or in the Command line, create a folder "TILECUT"
    (mkdir "TILECUT").
2.  Copy the file "TILECUT.BAS" into this folder on the SD Card image.
    This will involve the use of HDFmonkey - details are given below. 
3.  Draw your graphics and convert them to SL2 format, as in steps 2-4 above.
4.  Copy the .SL2 file to the "TILECUT" folder, with HDFmonkey.

As with a real next, copying the other files supplied is optional.


Installation and use of HDFmonkey
---------------------------------

1.  HDFmonkey, by Gasman (found here :https://github.com/gasman/hdfmonkey) has
    to be compiled from source, and I can't help with that. However, there are
    pre-compiled packages out there, such as this one for Windows on
    https://uto.speccy.org, for as long as the link lasts:
    https://uto.speccy.org/downloads/hdfmonkey_windows.zip
2.  Drop HDFmonkey.exe into your CSpect directory, and create a folder "SD2"
    (which will hold files to be transferred between the SD card image and your
    CSpect folder). HDFmonkey works on the command line, so it's easier to make
    a batch file that will do the job easily:
    hdfmonkey put cspect-next-2gb.img SD2\tilecut.bas TILECUT\tilecut.bas
    Save this as HDFMUP.BAT, and run it.
3.  ASIDE: Note that to get files off the SD card image, replace "put" with
    "get" and switch SD2 and TILECUT around (or whatever folder you're copying
    items from on the image). e.g.:
    hdfmonkey get cspect-next-2gb.img TILECUT\notes.txt SD2\notes.txt
    Save that as HDFMDOWN.BAT and edit it as necessary.


================================================================================


More technically...
-------------------

The TILE command (p.155-156 of the Issue 1 manual) isn't accompanied with any
example programs, so I had to work it out myself - with a bit of assistance
from existing Next, N-Go and CSpect users on Spectrum Computing, Discord and
That Website Beginning With F, You Know The One I Mean.

Knowing that the LAYER 2 screen was held in BANK 9 (top third), BANK 10 (middle
third) and BANK 11 (bottom third), my initial attempt was to capture a single
16×16 graphic, hand-drawn (i.e. with PLOT and DRAW) in the top left corner.
However, converting it to a tile was not as straightforward as:
BANK 9 COPY TO 47: TILE BANK 47
Attempting to defining the tile from this operation will only capture the top
line of the drawn graphic, because the screen isn't arranged the same way.

What we have on screen is, for an 8×8 tile:

     PLOT x --->
     0  1  2  3  4  5  6  7
   +--+--+--+--+--+--+--+--+
P 0|AA|AB|AC|AD|AE|AF|AG|AH|
L  +--+--+--+--+--+--+--+--+
O 1|BA|BB|BC|BD|BE|BF|BG|BH|
T  +--+--+--+--+--+--+--+--+
  2|CA|CB|CC|CD|CE|CF|CG|CH|
y  +--+--+--+--+--+--+--+--+
  3|DA|DB|DC|DD|DE|DF|DG|DH|
|  +--+--+--+--+--+--+--+--+
| 4|EA|EB|EC|ED|EE|EF|EG|EH|
|  +--+--+--+--+--+--+--+--+
V 5|FA|FB|FC|FD|FE|FF|FG|FH|
   +--+--+--+--+--+--+--+--+
  6|GA|GB|GC|GD|GE|GF|GG|GH|
   +--+--+--+--+--+--+--+--+
  7|HA|HB|HC|HD|HE|HF|HG|HH|
   +--+--+--+--+--+--+--+--+

And what we need, in order for the BANK... COPY TO... command to store the tile
data correctly, is for the graphic to be rearranged this way:

  PLOT x --->
  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18             61 62 63
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+           +--+--+--+
|AA|AB|AC|AD|AE|AF|AG|AH|BA|BB|BC|BD|BE|BF|BG|BH|CA|CB|CC| ...etc... |HF|HG|HH|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+           +--+--+--+

Likewise, for a 16×16 tile, the grid would be laid out with pixels labelled AA-AP in row y=0, BA-BP in row y=1, through to PA-PP for row y=15 (assuming we're using I and O in the letters, which we are). These are then rearranged similarly to the 8×8 tile, with pixel BA placed to the right of AP, and so on.

Tile Cutter starts by loading a 256×192 bitmap onto the screen, converted to
.SL2 format to make it compatible with LAYER 2 and its default colours. Only the
top third of the screen (BANK 9) is used for the conversion operation, allowing
64 large 16×16 tiles, or 256 small 8×9 tiles, to be converted in one session.
That should be enough for anyone, right?

The program has been designed so that the "cutting" process - i.e. the
rearrangement of screen-visible graphics to the linear format required for the
TILE command to work - is visible, as the graphics in BANK 9 are drawn into
BANK 10, the middle third of the screen. Then...
BANK 10 COPY TO 47: TILE BANK 47
...will produce a set of usable tile data in BANK 47.

To use these, a tile map is required, for which BANK 46 has been reserved.


The arcane mysteries of the tile map, solved
--------------------------------------------

The explanation of the TILE command, overall, is very terse. All the information
required is there, but is written in a way that is very difficult for raw
beginners to understand, and there are no example programs. The tile map - what
it is, how it works and how it is created - was where I found my first serious
roadblock in Next BASIC programming. Fortunately, after a few words with some
experts on Discord (hello, SevenFFF and AManInHisTechnoShed), I now understand
how it works, and part of this program demonstrates the tile map working.

The tile map, for LAYER 2 at least, is a series of bytes that point to positions
in the tile bank. One byte refers to one tile. The example tiles - i.e. those
generated by pressing D at the opening prompt - are all numbered in the same way
as they would be referred to in the tile map (albeit the small 8×8 tiles are in
hexadecimal, as there's only room for two digits).

To define the tile map, use the command:  TILE DIM b,o,w,t

- b is the BANK number to be used as the tile map - the whole map must be
    contained within one bank. I'm using BANK 46 in this program, for which the
    variable %m is defined in line 30; vary this to use a different bank for the
    tile map.
- o is the offset, i.e. how many bytes into that bank the tile map starts. In
    our case it is 0, but this allows for the definition of several tile maps in
    the same bank. More on this below.
- w is the width of the x-dimension of the tile map. When the test tiles are
    shown on screen in this program, they are arranged in a grid to fit the
    screen dimensions; the tile map is arranged to match that, although it
    doesn't necessarily have to be. Hence, for the set of 64 large tiles
    arranged 16(w)×4(h), w is set to 16 and the tiles in the x-dimension are
    numbered 0 to 15; the y-dimension is calculated automatically from that,
    and spans the whole bank.
- t is the tile size - and is either 8 (for 8×8 tiles) or 16 (for 16×16 tiles).
    No other values are possible.

To make the tiles usable in this program, the simplest possible tile map has
been defined - where each address in BANK 46 has been poked with itself, up to
the number of tiles defined. Hence, for the smaller tiles, addresses 0-255
contain the values 0-255, allowing each individual tile to be selected. The
addresses 256-16383 are still available for further tile maps - in which case,
a second tile map can be defined from address 256 onwards, and another TILE DIM
command with the offset (o) set to 256 will put this new tile map in use. To
revert to using the original tile map, use another TILE DIM command with the
original values.

The syntax of the TILE command to display the tiles has been given in the manual
but is not explained in any detail. So I will.

Load the program and draw the set of large test tiles - the explanations below
will refer to this tile pattern as it is seen on screen.

TILE w,h AT mx,my TO px,py

- w , h are the width and height of the section of the tile map to be displayed.
        If both are set to 1, this will show a single tile; if either are
        greater than 1, this will print a mosaic of tiles, as they are laid out
        in the tile map, starting with the top left. Hence, TILE 2,2... if taken
        from the first position in the tile map, will display tiles 0, 1, 16 and
        17 in a 2×2 square, with 16 and 17 underneath 0 and 1.
- mx,my are the positions from within the tile map that the tiles are taken
        from. Tile 42 is at position mx=10, my=2 as defined in this program -
        but will be a different position if the width parameter in the TILE DIM
        command is changed!
- px,py are the positions on screen at which the tile will be printed - but this
        only corresponds to the PRINT AT position in the case of 8×8 tiles; the
        grid resolution is halved for large tiles, i.e. px ranges from 0 to 15
        and py from 0 to 11.

Some examples from the large tile set, using the tile map built by the program:

- TILE 1,1 AT 4,2 TO 15,11 prints tile 36 at the bottom right of the screen.

- TILE 2,2 AT 11,1 TO 7,5 prints a square of tiles 27,28,43,44 in the centre of
  the screen. This can also be achieved in multiple commands:
  = TILE 1,2 AT 11,1 TO 7,5: TILE 1,2 AT 12,1 TO 8,5
  = TILE 2,1 AT 11,1 TO 7,5: TILE 2,1 AT 11,2 TO 7,6
  = TILE 1,1 AT 11,1 TO 7,5: TILE 1,1 AT 12,1 TO 7,6: TILE 1,1 AT 11,2 TO 8,5:
    TILE 1,1 AT 12,2 TO 8,6

To demonstrate a slightly more complex tile map, suppose you want to print a
sequence of the eight tiles with square numbers, 0² to 7², at the top left of
the screen. Either print the individual tiles with the tile map as it is:
- TILE 2,1 AT 0,0 TO 0,0: REM tiles 0 and 1
  TILE 1,1 AT 4,0 TO 2,0: REM tile 4
  TILE 1,1 AT 9,0 TO 3,0: REM tile 9
  TILE 1,1 AT 0,1 TO 4,0: REM tile 16
  TILE 1,1 AT 9,1 TO 5,0: REM tile 25
  TILE 1,1 AT 4,2 TO 6,0: REM tile 36
  TILE 1,1 AT 1,3 TO 7,0: REM tile 49

Another approach would be to redimension the tile map so that it has width 64,
and all the tiles numbered n are on column n, row 0 of the tile map:
- TILE DIM 46,0,64,16
  TILE 2,1 AT 0,0 TO 0,0: REM tiles 0 and 1
  TILE 1,1 AT 4,0 TO 2,0: REM I think you see where this is going...
  TILE 1,1 AT 9,0 TO 3,0
  TILE 1,1 AT 16,0 TO 4,0
  TILE 1,1 AT 25,0 TO 5,0
  TILE 1,1 AT 36,0 TO 6,0
  TILE 1,1 AT 49,0 TO 7,0

Or - and this is the way you'd approach it if you were going to use the tiles to
make an entire screen layout - make a new tile map with all eight tiles in sequence (starting at address 256 in BANK 46), use TILE DIM to point to that new
map, and use one TILE command to print them all at once:
- FOR %n=0 TO 7: READ %v: BANK 46 POKE %256+n,%v: NEXT n
  DATA 0,1,4,9,16,25,36,49
  TILE DIM 46,256,16,16
  TILE 8,0 AT 0,0 TO 0,0: REM (or just TILE 8,0 will do it...)

This last mention makes it easy to fill a screen with specific tiles. For the
larger tile size, the tile map would be 192 bytes long (16×12) with every
position on the screen accounted for, arranged by column, then row (i.e. the
first 16 bytes refer to the tiles for the top row, the next 16 bytes for the
second row, and so on). Use the TILE DIM command to refer to where the new tile
map is in memory, then use the standalone command TILE to blitz the entire map
onto the screen at once.

It would be advantageous to define one tile (probably tile 0) as entirely
transparent, to function as a blank. To produce a screen with a border of tile
63, with blanks in between, this requires 63 to be poked to the first 16
addresses of the tile map, then ten blocks of 63, 14 zeroes and another 63, then
a final 16 63s.

Learn by doing. Define some tiles, experiment with tile maps, and it'll be
cracked in no time.

The concept, that is, not the tiles. They're not ceramic.


- JRW 14/1 MMXXIII
